#include <vector>

#include "libnoscript.hpp"

using noscript::Cmd;
using noscript::CxxEnv;
using noscript::CxxTarget;
using noscript::ERR_OK;
using noscript::Error;
using noscript::Path;

static bool is_whitespace(int c)
{
    switch (c) {
    case ' ':
    case '\r':
    case '\n':
    case '\t':
        return true;
    default:
        return false;
    }
}

static size_t skip_ws(std::string const& text, size_t offset)
{
    for (size_t i = offset; i < text.size(); ++i) {
        if (!is_whitespace(text[i])) {
            return i;
        }
    }

    return std::string::npos;
}

static size_t until_ws(std::string const& text, size_t offset)
{
    for (size_t i = offset; i < text.size(); ++i) {
        if (is_whitespace(text[i])) {
            return i;
        }
    }

    return std::string::npos;
}

static void split(std::string const& text, std::vector<std::string>* out)
{
    size_t offset = 0;

    while (true) {
        offset = skip_ws(text, offset);
        if (offset == std::string::npos)
            break;

        size_t n = until_ws(text, offset);

        if (n == std::string::npos) {
            out->push_back(text.substr(offset));
            break;
        }

        out->push_back(text.substr(offset, n - offset));
        offset = n;
    }
}

static Error runtime(int argc, char** argv)
{
    NOSCRIPT_TRY(noscript::RebuildNoScript(argc, argv));
    NOSCRIPT_TRY(noscript::GetCxxCmd().Arg("--version").Run());

    auto wx_cxxflags = noscript::Cmd { "wx-config" }
                           .Arg("--toolkit=gtk3")
                           .Arg("--cxxflags")
                           .GetOutput();

    auto wx_ldflags = noscript::Cmd { "wx-config" }
                          .Arg("--toolkit=gtk3")
                          .Arg("--libs")
                          .GetOutput();

    CxxEnv env;

    env.build_type = CxxEnv::RELEASE;
    env.target_link_type = CxxEnv::SHARED;

    split(wx_cxxflags.child_stdout, &env.cxx_flags);
    split(wx_ldflags.child_stdout, &env.ld_flags);

    CxxTarget main(&env, "main", CxxTarget::EXECUTABLE, CxxEnv::AUTO_LINK);
    main.Src(Path() / "main.cpp");

    NOSCRIPT_TRY(main.Build());
    NOSCRIPT_TRY(Cmd(main.GetTargetPath()).Run());

    NOSCRIPT_LOG(INFO, "done");
    return ERR_OK;
}

int main(int argc, char** argv)
{
    Error err = runtime(argc, argv);

    if (err != ERR_OK) {
        return 1;
    }
    return 0;
}
